#include "../../../hw_ints.h"
#include "../../../hw_memmap.h"
#include "../../../hw_types.h"
#include "../../../src/adc.h"
#include "../../../src/debug.h"
#include "../../../src/gpio.h"
#include "../../../src/interrupt.h"
#include "../../../src/sysctl.h"
#include "../../../src/timer.h"
#include "../../../src/uart.h"
#include "../osram96x16x1.h"

static unsigned char g_pucTetrisMatrix[192] = {0};

//
// figurite trqbva da se prepravqt nanovo i da se podravnqt na lqvo i nadolu ( za da se spestqt nepriqtnosti )
//
  
static unsigned char g_pucFigures[19][8] = { 	
												{ 0x0f,0x0f,0x0f,0x0f,0x00,0x00,0x00,0x00 },
												{ 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00 },
												{ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03 },
												{ 0x30,0x30,0x3c,0x3c,0x0c,0x0c,0x00,0x00 },
												{ 0x0f,0x0f,0x3c,0x3c,0x00,0x00,0x00,0x00 },
												{ 0x0c,0x0c,0x3c,0x3c,0x30,0x30,0x00,0x00 },
												{ 0x3c,0x3c,0x0f,0x0f,0x00,0x00,0x00,0x00 },
												{ 0x3f,0x3f,0x30,0x30,0x00,0x00,0x00,0x00 },
												{ 0x0f,0x0f,0x03,0x03,0x03,0x03,0x00,0x00 },
												{ 0x03,0x03,0x3f,0x3f,0x00,0x00,0x00,0x00 },
												{ 0x3c,0x3c,0x30,0x30,0x30,0x30,0x00,0x00 },
												{ 0x30,0x30,0x3f,0x3f,0x00,0x00,0x00,0x00 },
												{ 0x3c,0x3c,0x30,0x30,0x30,0x30,0x00,0x00 },
												{ 0x3f,0x3f,0x03,0x03,0x00,0x00,0x00,0x00 },
												{ 0x0c,0x0c,0x0c,0x0c,0x3c,0x3c,0x00,0x00 },
												{ 0x3f,0x3f,0x0c,0x0c,0x00,0x00,0x00,0x00 },
												{ 0x0c,0x0c,0x3c,0x3c,0x0c,0x0c,0x00,0x00 },
												{ 0x0c,0x0c,0x3f,0x3f,0x00,0x00,0x00,0x00 },
												{ 0x0c,0x0c,0x0f,0x0f,0x0c,0x0c,0x00,0x00 }
											};

// tozi masiv 6te se pozlva za vujdane na sledva6tata rotaciq na teku6tiq element ( ne se setih za po-umen i udoben)
static const unsigned char g_pucRot[19] = { 0, 2, 1, 4, 3, 6, 5, 8, 9, 10, 7, 12, 13, 14, 11,16,17,18,15 };

static unsigned char g_pucDisplayBuf[20] = { 0 };
static unsigned char g_pucLastNoCollision[16] = { 0 };

void UpdateTetrixMatrix(unsigned long ulRowOffset)
{
	unsigned char ucIdx;

	for( ucIdx = 0; ucIdx < 8 ; ucIdx +=4 )
	{
		*(unsigned long *) (g_pucTetrisMatrix + 88 - ulRowOffset + ucIdx ) |=
								*(unsigned long *)(g_pucLastNoCollision + ucIdx);
								
		*(unsigned long *) (g_pucTetrisMatrix + 184 - ulRowOffset + ucIdx ) |=
								*(unsigned long *)(g_pucLastNoCollision + 8 + ucIdx ); 
	}
}

void ClearDisplayBuf(void)
{
	unsigned char ucIdx;

	for( ucIdx = 0; ucIdx < 20 ; ucIdx +=4 )
	{
		*(unsigned long *) (g_pucDisplayBuf + ucIdx ) = 0;
	}
}

void CopyToLastNoCollision(void)
{
	unsigned char ucIdx;

	for( ucIdx = 0; ucIdx < 8 ; ucIdx +=4 )
	{
		*(unsigned long *) (g_pucLastNoCollision + ucIdx ) = 
						*(unsigned long *) (g_pucDisplayBuf + ucIdx );

		*(unsigned long *) (g_pucLastNoCollision + 8 + ucIdx ) = 
						*(unsigned long *) (g_pucDisplayBuf + 10 + ucIdx );

	}
}

int main(void)
{
	unsigned long ulPos, ulCount, ulBits = 0 , ulShape = 0 , ulRowOffset = 0 , ulDelay = 0;
	unsigned char ucRotFlag = 0;
    //
    // Set the clocking to run at 20MHz from the PLL.
    //
    SysCtlClockSet(SYSCTL_SYSDIV_10 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_6MHZ);


	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC);
	
	
	GPIOPinTypeGPIOInput(GPIO_PORTC_BASE , GPIO_PIN_4 );
    
	ADCSequenceConfigure(ADC_BASE , 0 , ADC_TRIGGER_PROCESSOR, 0);
	ADCSequenceStepConfigure(ADC_BASE,0,0,ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);
	ADCSequenceEnable(ADC_BASE,0);
	//
    // Initialize the OLED display.
    //
    OSRAM96x16x1Init(true);
	
	while(1)
	{

		//test
		ADCProcessorTrigger(ADC_BASE, 0);
		while(!ADCIntStatus(ADC_BASE , 0 , false ) );
		ADCSequenceDataGet(ADC_BASE, 0 , &ulPos );

		ulPos = ( (ulPos*7)/1023) << 1;

		if( !GPIOPinRead(GPIO_PORTC_BASE , GPIO_PIN_4 ) )
		{
			while( !GPIOPinRead(GPIO_PORTC_BASE , GPIO_PIN_4 ) );
			ucRotFlag = 1;
		}
		if( ucRotFlag )
		{
			ulShape = g_pucRot[ulShape];
			ucRotFlag = 0;
		} 
		//end test
		newFigure:
		//ulPos = 2; //( (ulPos/2 + 1) & 0x07 ) << 1;
		if( ulRowOffset > 88 ) {
			UpdateTetrixMatrix(ulRowOffset-2);
			ulRowOffset = 0;				    
		}
		if( !ulRowOffset )
			ulShape = ( ulShape + 1 ) % 19 ;
		for( ulCount = 0 ; ulCount < 8 ; ulCount++ )
		{
			 if(ulPos < 8 )
			 {
			 	ulBits = ( g_pucFigures[ulShape][ulCount] << ulPos ) & 0xff;
				if(ulBits)
				{
					g_pucDisplayBuf[ulCount] =  g_pucTetrisMatrix[88 - ulRowOffset + ulCount] ^ ulBits;
					if( ( g_pucDisplayBuf[ulCount] & ulBits ) != ulBits )
					{ // rotation flag and move flag check
						UpdateTetrixMatrix(ulRowOffset - 2);
						ulRowOffset = 0;
						ulShape = ( ulShape + 1 ) % 19 ;
						goto newFigure;
					}
				}
				ulBits =  g_pucFigures[ulShape][ulCount] >> ( 8 - ulPos );
				if(ulBits)
				{
					g_pucDisplayBuf[10 + ulCount] = g_pucTetrisMatrix[184 - ulRowOffset + ulCount] ^ ulBits;
					if( (g_pucDisplayBuf[10 + ulCount] & ulBits ) != ulBits )
					{
						UpdateTetrixMatrix(ulRowOffset - 2);
						ulRowOffset = 0;
						ulShape = ( ulShape + 1 ) % 19 ;
						goto newFigure;
					}
				}	 
			 }
			 else
			 {	 // da se OPRAVI!
			 	ulBits = g_pucFigures[ulShape][ulCount] << ( ulPos - 8 );
				if( (ulBits & 0xff00 ) == 0 ) // ako != 0 zna4i imame colizia i 
				{							  // produljavame izpulnenieto po block shemata
					g_pucDisplayBuf[10 + ulCount] = g_pucTetrisMatrix[184 - ulRowOffset + ulCount] ^ ulBits;
					if( ( g_pucDisplayBuf[10 + ulCount] & ulBits ) != ulBits )
					{
						UpdateTetrixMatrix(ulRowOffset - 2);
						ulRowOffset = 0;
						goto newFigure;						
					}
				}
				else
				{
						UpdateTetrixMatrix(ulRowOffset - 2);
						ulRowOffset = 0;
						goto newFigure;
				}
			 }
		}
		for( ; ulCount < 10 ; ulCount++ )
		{
			g_pucDisplayBuf[ ulCount ] ^=  g_pucTetrisMatrix[ 88 - ulRowOffset + ulCount ];
			g_pucDisplayBuf[ 10 + ulCount ] ^=  g_pucTetrisMatrix[ 184 - ulRowOffset + ulCount ]; 
		}



		OSRAM96x16x1ImageDraw( g_pucDisplayBuf  , 88 - ulRowOffset  , 0 , 10 , 2  );
		ulRowOffset+=2;
		CopyToLastNoCollision();
		ClearDisplayBuf();
		while(ulDelay++ < 200000 );
		ulDelay =0;

	}
		
}
